%{

using namespace std;

#include "document.h"
#include "node.h"
#include "attr_node.h"
#include "element.h"
#include "attribute.h"
#include "content_node.h"
#include "spec_node.h"
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <list>
#include "commun.h"
#include "xml.tab.h"





// ces trois fonctions devront changer de nom dans le cas où l'otion -p est utilisée
int xmlwrap(void);
void xmlerror(Document* doc, char *msg);
int xmllex(void);

%}

%union {
   char * s;
   ElementName * en;  /* le nom d'un element avec son namespace, cf commun.h */
   list<XmlAttribute*> *listAttr;
   list<Node*> *listNode;
   XmlElement* elem;
   Document* doc;
   SpecNode* spec;
}

%token EGAL SLASH SUP SUPSPECIAL DOCTYPE
%token <s> ENCODING VALEUR DONNEES COMMENT NOM ENNOM
%token <en> OBALISEEN OBALISE OBALISESPECIALE FBALISE FBALISEEN
%type <listAttr> attributs_opt
%type <listNode> contenu_opt vide_ou_contenu ferme_contenu_et_fin declarations
%type <elem> element ouvre
%type <doc> document
%type <spec> declaration


//%parse-param { char* dtd } // john : chemin du fichier de DTD
%parse-param { Document* doc } // john : document

%%

document
 : declarations element misc_seq_opt { doc->setRoot($2); }
 ;
misc_seq_opt
 : misc_seq_opt misc
 | /*vide*/
 ;
misc
 : COMMENT
 ;

declarations
 : declarations declaration
 | /*vide*/
 ;
 
declaration
 : DOCTYPE NOM NOM VALEUR SUP { doc->setNsFile($4); free($2);free($3);free($4); } //{ strcpy(dtd, $4); }
 ;

element
 : ouvre attributs_opt vide_ou_contenu { $$ = $1; $$->setAttributes($2); $$->setChildren($3); }  
 ;
ouvre
 : OBALISE { $$ = new XmlElement($1->second); delete $1; }
 | OBALISEEN { $$ = new XmlElement($1->second, $1->first); delete $1; }
 ;
vide_ou_contenu
 : SLASH SUP { $$ = new list<Node*>; }
 | ferme_contenu_et_fin SUP { $$ = $1; }
 ;
ferme_contenu_et_fin
 : SUP contenu_opt FBALISE { $$ = $2; delete $3;  }
 | SUP contenu_opt FBALISEEN { $$ = $2; delete $3; }
 ;
contenu_opt 
 : contenu_opt DONNEES { $$ = $1; $$->push_back(new ContentNode($2)); free($2); }
 | contenu_opt misc 
 | contenu_opt element { $$ = $1; $$->push_back($2); }
 | /*vide*/ { $$ = new list<Node*>; }          
 ;
attributs_opt
 : attributs_opt NOM EGAL VALEUR { $$ = $1; $$->push_back(new XmlAttribute($2, $4)); free($2); free($4); }
 | attributs_opt ENNOM EGAL VALEUR { $$ = $1; $$->push_back(new XmlAttribute($2, $4)); free($2); free($4); }
 | /*vide*/ { $$ = new list<XmlAttribute*>; }
 ;

%%

#ifdef STANDALONE

int main(int argc, char **argv)
{
  int err;


  xmldebug = 1; // pour enlever l'affichage de l'éxécution du parser, commenter cette ligne

  Document* doc = new Document;

  err = xmlparse(doc);
  if (err != 0) printf("Parse ended with %d error(s)\n", err);
  	else  printf("Parse ended with success\n");

  if(doc != NULL)
  {
    doc->print(cout);

    printf("DTD file is '%s'.\n", doc->getNsFile().c_str());
  }

  delete doc;
  
  return 0;
}

#endif

int xmlwrap(void)
{
  return 1;
}

void xmlerror(Document* doc, char *msg)
{
  fprintf(stderr, "%s\n", msg);
}

